package org.apache.lucene.distributed.cl;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

import org.apache.lucene.distributed.LuceneClasses;
import org.apache.lucene.distributed.RMIClasses;
import org.apache.lucene.distributed.ResolverUtil;
import org.apache.lucene.distributed.RMI.DefaultClassAccept;
import org.apache.lucene.distributed.RMIClasses.ClassAccept;
import org.apache.lucene.distributed.RMIClasses.ClassKey;

public class Depends {
  public final Set<ClassKey> classKeys;
  ClassAccept classAccept;
  Set<String> rootClasses;

  public static void main(String[] args) throws Exception {
    Set<String> roots = new HashSet<String>();
    //roots.add("org.apache.lucene.search.highlight.Highlighter");
    roots.add("org.apache.lucene.search.BooleanQuery");
    Depends depends = new Depends(roots, new DefaultClassAccept(new HashSet<String>()), true);
    System.out.println(depends.classKeys + "");
  }

  public Depends(Set<String> rootClasses, ClassAccept classAccept, boolean resolve) throws Exception {
    this.rootClasses = rootClasses;
    this.classAccept = classAccept;
    classKeys = new HashSet<ClassKey>();
    for (String className : rootClasses) {
      ClassDepends classDepends = new ClassDepends(classAccept);
      Set<String> cls = new HashSet<String>(classDepends.run(className));
      if (resolve) {
        ResolverUtil resolverUtil = new ResolverUtil();
        for (String rootName : cls) {
          Class cl = Class.forName(rootName);
          resolverUtil.findImplementations(cl, "");
        }
        Set<Class> rclasses = resolverUtil.getClasses();
        for (Class c : rclasses) 
          cls.add(c.getName());
      }
      classKeys.addAll(getClassKeys(cls));
    }
  }

  private Set<ClassKey> getClassKeys(Set<String> cls) throws Exception {
    for (String c : cls) {
      if (classAccept.isSpecial(c)) {
        try {
          Class clasz = Class.forName(c);
          String resource = RMIClasses.classToResource(c);
          Long serialVersionUID = null;
          try {
            Field field = clasz.getDeclaredField("serialVersionUID");
            serialVersionUID = (Long) field.get(null);
          } catch (NoSuchFieldException nsfe) {
            //InputStream input = clasz.getClassLoader().getResourceAsStream(resource);
            
          }
          classKeys.add(new ClassKey(c, serialVersionUID));
        } catch (Exception ex) {
          throw new Exception(c, ex);
        }
      }
    }
    return classKeys;
  }
}
